package org.colin.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.colin.Tools.DateUtil;
import org.colin.Tools.TokenUtil;
import org.colin.Tools.Tool;
import org.colin.mapper.SysResourceMapper;
import org.colin.model.ro.SysResourceRO;
import org.colin.model.vo.MenuTree;
import org.colin.model.vo.MenuVO;
import org.colin.model.vo.Result;
import org.colin.model.vo.SysResourceVO;
import org.colin.model.vo.UserVO;
import org.colin.service.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Service
public class ResourceServiceImpl implements ResourceService {

	@Autowired
	private SysResourceMapper sysResourceMapper;

	@Autowired
	private TokenUtil tokenUtil;

	@Override
	public Result insert(SysResourceRO resource) {
		resource.setId(Tool.getPrimaryKey());
		resource.setCreateTime(DateUtil.getCurrentDate());
		resource.setUpdateTime(DateUtil.getCurrentDate());
		if (Tool.isBlank(resource.getParentId())) {
			resource.setParentId("0");
		}
		// 根据接口路径自动转换权限字符串
		if (!Tool.isBlank(resource.getUrl())) {
			String url = resource.getUrl();
			if (url.startsWith("/")) {
				url = url.substring(1);
			}
			resource.setPermission(url.replace("/", ":"));
		}
		int result = sysResourceMapper.insert(resource);
		if (result == 1) {
			return Result.success();
		} else {
			return Result.fail();
		}
	}

	@Override
	public Result delete(String id) {
		int result = sysResourceMapper.deleteByPrimaryKey(id);
		if (result == 1) {
			return Result.success();
		} else {
			return Result.fail();
		}
	}

	@Override
	public Result<SysResourceVO> selectAll(SysResourceRO resource) {
		List<SysResourceVO> list = sysResourceMapper.selectAll(resource);
		return Result.success(list);
	}

	@Override
	public Result update(SysResourceRO resource) {
		resource.setUpdateTime(DateUtil.getCurrentDate());
		// 根据接口路径自动转换权限字符串
		if (!Tool.isBlank(resource.getUrl())) {
			String url = resource.getUrl();
			if (url.startsWith("/")) {
				url = url.substring(1);
			}
			resource.setPermission(url.replace("/", ":"));
		}
		int result = sysResourceMapper.update(resource);
		if (result == 1) {
			return Result.success();
		} else {
			return Result.fail();
		}
	}

	// 菜单初始化
	@Override
	public Result menuInit() {
		UserVO user = tokenUtil.getRedisUser();
		List<MenuVO> menuList = sysResourceMapper.menuInit(user.getId());

		List<String> keyList = new ArrayList<>();
		for (MenuVO menuVo : menuList) {
			keyList.add(menuVo.getId());
		}
		List<MenuVO> newList = new ArrayList<>();
		for (MenuVO menuVo : menuList) {
			// 递归查询到顶级节点
			findParentMenu(menuVo, keyList, newList);
		}
		if (!CollectionUtils.isEmpty(newList)) {
			menuList.addAll(newList);
		}
		// 将集合转换成树形集合(前端需要的数据格式)
		List<MenuVO> treeList = this.listToTreeList(menuList);
		return Result.success(treeList);
	}

	/**
	 * @desc 将list转换成树形结构集合
	 * @author wujiangbo
	 * @date 2020年1月4日 上午10:56:39
	 * @param list 需要转化的数据
	 * @return List<MenuVO> 转换后的树形结构集合
	 */
	private List<MenuVO> listToTreeList(List<MenuVO> list) {
		List<MenuVO> treeList = new ArrayList<>();
		if (CollectionUtils.isEmpty(list)) {
			return treeList;
		}
		Map<String, MenuVO> map = new HashMap<>();
		// 将菜单集合数据存放到map集合中，key为菜单id，后续判断父节点用
		for (MenuVO menuVO : list) {
			map.put(menuVO.getId(), menuVO);
			// 将一级节点添加到树形集合中
			if (Tool.isBlank(menuVO.getParentId()) || "0".equals(menuVO.getParentId())) {
				treeList.add(menuVO);
			}
		}
		// 遍历结果集
		for (MenuVO menuVO : list) {
			if (Tool.isBlank(menuVO.getParentId()) || "0".equals(menuVO.getParentId())) {
				// 跳过一级节点
				continue;
			}
			// 判断父节点是否存在
			MenuVO parentMenu = map.get(menuVO.getParentId());
			if (parentMenu != null) {
				// 父节点存在，则将该节点添加到父节点的子节点集合中
				parentMenu.getChildren().add(menuVO);
			}
		}
		return treeList;
	}

	/**
	 * @desc 递归查询上级菜单，一直查到一级菜单
	 * @author wujiangbo
	 * @date 2020年1月4日 上午10:55:10
	 * @param menuVO   需要递归查询的菜单对象
	 * @param keyList  已查询到的菜单id集合
	 * @param menuList 递归查询到的数据存放集合
	 */
	private void findParentMenu(MenuVO menuVO, List<String> keyList, List<MenuVO> menuList) {
		if (Tool.isBlank(menuVO.getParentId()) || "0".equals(menuVO.getParentId()) || keyList.contains(menuVO.getParentId())) {
			// 一级节点、已存在节点 则跳过
			return;
		}
		MenuVO menu = this.sysResourceMapper.selectMenuById(menuVO.getParentId());
		if (menu != null) {
			menuList.add(menu);
			keyList.add(menuVO.getParentId());
			// 递归查询到顶级节点
			findParentMenu(menu, keyList, menuList);
		}
	}

	@Override
	public Result menuInitEasyUI() {
		UserVO user = tokenUtil.getRedisUser();
		List<MenuVO> menuList = sysResourceMapper.menuInit(user.getId());
		List<MenuTree> treeList = new ArrayList<MenuTree>();
		if (menuList != null && !menuList.isEmpty()) {
			MenuTree tree = null;
			for (int i = 0; i < menuList.size(); i++) {
				tree = new MenuTree();
				MenuVO vo = menuList.get(i);
				tree.setId(vo.getId());
				tree.setText(vo.getNameCn());
				tree.setPId(vo.getParentId());
				tree.setUrl(vo.getUrl());
				tree.setIconCls(vo.getIcon());
				tree.setSort(vo.getSortNo());
				treeList.add(tree);
			}
		}
		return Result.success(getTree(treeList));
	}

	/**
	 * @desc 构造树流程
	 * @author wujiangbo
	 * @date 2020年1月19日 下午2:29:39
	 * @param list
	 * @return
	 */
	private ArrayList<MenuTree> getTree(List<MenuTree> list) {
		// 首先，我们创建一个链表，用于存放第一层，也就是最高层节点
		ArrayList<MenuTree> tree = new ArrayList<>();
		// 循环遍历父节点
		for (MenuTree treeNode : list) {
			// 如果是根节点或者父节点，就构造树，我们这里pId=0代表最高层级，没有父节点的意思。
			if ("0".equals(treeNode.getPId()) || treeNode.getId().equals(treeNode.getPId())) {
				// 如果寻找到最高层了，然后我们就往下找它的子节点，把它的ID和之前表中所有数据构成的链表一同传到getChildrenNode方法中，去寻找自己的孩子
				treeNode.setChildren(getChildrenNode(treeNode.getId(), list));
				// 把我们的父节点放进链表中
				tree.add(treeNode);
			}
		}
		// 返回我们装好的树
		return tree;
	}

	/**
	 * @desc 找到父节点的子节点
	 * @author wujiangbo
	 * @date 2020年1月19日 下午2:30:00
	 * @param pid
	 * @param list
	 * @return
	 */
	private ArrayList<MenuTree> getChildrenNode(String pid, List<MenuTree> list) {
		/**
		 * 我们拿到了父节点的ID，和所有数据的链表之后，来到了这里，首先，申明一个链表，用于存放二级的节点。
		 * 等会会调用递归，要注意，调用的递归ArrayList<MenuTree>所代表的意义不是一样的，所以，调用n次就代表这里的链表存放的是n+2次的层级节点。
		 */
		ArrayList<MenuTree> childrenNode = new ArrayList<>();
		// 循环遍历子节点
		for (MenuTree treeNode : list) {
			// 如果节点是父节点，继续往下找到其子节点
			if (pid.equals(treeNode.getPId())) {
				treeNode.setChildren(getChildrenNode(treeNode.getId(), list));// 继续调用自身方法，去寻找接下来pid的子节点的子节点。。。。，以此不断下去，就能把所有的遍历完了
				// 这里可能会有好几个节点是pid的子节点，所以用链表childrenNode装起来。
				childrenNode.add(treeNode);
			}
		}
		return childrenNode;
	}
}
